package umls.interfaces.Pathways;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.LinkedList;
import java.util.List;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.xpath.XPathExpressionException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.w3c.tidy.Tidy;
import org.xml.sax.SAXException;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXNotSupportedException;

import umls.interfaces.pathways.server.jaxb.ErrorType;
import umls.interfaces.pathways.server.jaxb.ExtendedRecordType;
import umls.interfaces.pathways.server.jaxb.PathwayType;
import umls.interfaces.pathways.server.jaxb.SearchResponseType;
/**
 * This class is used to wrap all the usefull information from the pathway's common site
 * @author melo
 *
 */
public class Pathways {
	static String urlStr = "http://www.pathwaycommons.org/pc/webservice.do";
	static JAXBContext jc;
	static Unmarshaller u;

	/**
	 * 
	 */
	public Pathways() {
		try {
			jc = JAXBContext
					.newInstance("umls.interfaces.pathways.server.jaxb");
			u = jc.createUnmarshaller();
		} catch (Exception e) {
			System.err.println(e.toString());
		}
	}

	public List<String> get_from_cclass(String ID) {
		return null;

	}

	private static Element getRootTable(Document element)
			throws XPathExpressionException {
		NodeList nl = (NodeList) element.getElementsByTagName("table");
		int length = nl.getLength();

		for (int i = 0; i < length; i++) {
			Element n = (Element) nl.item(i);
			// table cellpadding="2" cellspacing="0" border="0" width="100%">
			if (n.getTagName().equals("table")
					&& n.getAttribute("cellpadding").equals("2")
					&& n.getAttribute("border").equals("0")
					&& n.getAttribute("width").equals("100%"))
				return n;

		}
		return null;

	}

	public static List<String> getIDFromKeyword(String keyword)
			throws IOException {
		URL query = new URL(
				"http://www.pathwaycommons.org/pc/webservice.do?version=3.0&q="
						+ keyword
						+ "&format=html&cmd=get_by_keyword&snapshot_id=GLOBAL_FILTER_SETTINGS&record_type=PATHWAY");
		Tidy tidy = new Tidy();
		tidy.setQuiet(true);
		tidy.setShowWarnings(false);
		Document response = tidy.parseDOM(query.openStream(), null);
		List<String> result = new LinkedList<String>();
		Element table = null;
		try {
			table = getRootTable(response);
		} catch (XPathExpressionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		NodeList nl = table.getChildNodes();
		for (int i = 0; i < nl.getLength(); i++) {
			if (nl.item(i).getNodeName().equals("tr")
					&& ((Element) nl.item(i)).getAttribute("valign")
							.equalsIgnoreCase("top")) {

				NodeList img = ((Element) nl.item(i))
						.getElementsByTagName("img");
				// System.out.println(((Element)img.item(0)).getAttribute("width"));
				int affinity = Integer.parseInt(((Element) img.item(0))
						.getAttribute("width"));
				if (affinity >= 50) {
					NodeList idlist = ((Element) nl.item(i))
							.getElementsByTagName("a");
					String[] CPATH_ID = ((Element) idlist.item(0))
							.getAttribute("href").split("=");
					result.add(CPATH_ID[1]);
				}
			}
		}
		return result;

	}

	public static List<String> getGenes(String process) throws IOException {
		List<String> result = new LinkedList<String>();
		List<String> IDs = getIDFromKeyword(process);
		for (String id : IDs) {
			result.addAll(getGeneFromIDs(id));
		}

		return result;
	}

	public static List<String> getGeneFromIDs(String id) throws IOException {
		BufferedReader rd = null;

		// http://www.pathwaycommons.org/pc/webservice.do?version=2.0&cmd=get_record_by_cpath_id&q=826370&output=gsea&output_id_type=GENE_SYMBOL
		URL url;
		try {
			url = new URL(
					"http://www.pathwaycommons.org/pc/webservice.do?version=2.0&cmd=get_record_by_cpath_id&q="
							+ id + "&output=gsea&output_id_type=GENE_SYMBOL");
			URLConnection conn = url.openConnection();
			rd = new BufferedReader(
					new InputStreamReader(conn.getInputStream()));
		} catch (MalformedURLException e) {

			e.printStackTrace();
		}
		StringBuilder sb = new StringBuilder();
		String temp = null;
		while ((temp = rd.readLine()) != null) {
			sb.append(temp);
		}
		rd.close();
		// rd.readLine();
		String[] genes = sb.toString().split("\t");
		List<String> result = new LinkedList<String>();
		for (int i = 2; i < genes.length; i++)
			if (!genes[i].equalsIgnoreCase("NOT_SPECIFIED"))
				result.add(genes[i]);
		return result;
	}

	public LinkedList<String> getProcesses(String gene) {
		LinkedList<String> result = new LinkedList<String>();
		Object a = null;
		try {
			String query = "?version=2.0&q=" + gene + "&format=xml&cmd=search";
			a = u.unmarshal(search(query));
			JAXBElement<SearchResponseType> ris = safeCast(a);
			SearchResponseType risposta = ris.getValue();
			for (ExtendedRecordType ert : risposta.getSearchHit()) {
				for (PathwayType ptwlist : ert.getPathwayList().getPathway()) {
					result.add(ptwlist.getName());
				}

			}
		} catch (ClassCastException e) {
			@SuppressWarnings("unchecked")
			JAXBElement<ErrorType> jerr = (JAXBElement<ErrorType>) (a);
			ErrorType err = jerr.getValue();
			System.out.println("Errore " + err.getErrorCode());
		}

		catch (JAXBException e) {
			e.printStackTrace();
		}
		return result;

	}

	@SuppressWarnings(value = "unchecked")
	private static JAXBElement<SearchResponseType> safeCast(Object o) {
		return (JAXBElement<SearchResponseType>) o;
	}

	public static BufferedReader search(String query) {
		if (query == null) {
			return null;
		}
		BufferedReader rd = null;

		try {
			URL url = new URL(urlStr + query);
			URLConnection conn = url.openConnection();
			// Get the response
			rd = new BufferedReader(
					new InputStreamReader(conn.getInputStream()));
		} catch (Exception e) {
			e.printStackTrace();
		}
		return rd;
	}

	public static InputStream search2(String query) {
		if (query == null) {
			return null;
		}
		BufferedReader rd = null;

		URL url;
		try {
			url = new URL(urlStr + query);
			URLConnection conn = url.openConnection();
			return conn.getInputStream();
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return null;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return null;
		}

	}

	@SuppressWarnings("unused")
	private static BufferedReader rawSearch(String query) {
		if (query == null) {
			return null;
		}
		BufferedReader rd = null;

		try {

			URL url = new URL(urlStr + query);
			URLConnection conn = url.openConnection();
			// Get the response
			rd = new BufferedReader(
					new InputStreamReader(conn.getInputStream()));
		} catch (Exception e) {
			e.printStackTrace();
		}
		return rd;

	}

	private List<String> parseResponse(InputStream br) {
		SAXParserFactory factory = SAXParserFactory.newInstance();
		SaxParser saxHandler = new SaxParser();
		SAXParser saxParser = null;
		factory.setValidating(false);
		// List<String> result=null;
		try {
			factory
					.setFeature(
							"http://apache.org/xml/features/nonvalidating/load-external-dtd",
							false);
			saxParser = factory.newSAXParser();
			saxParser.parse(br, saxHandler);
		} catch (SAXNotRecognizedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SAXNotSupportedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ParserConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SAXException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return saxHandler.getGenes();

	}
}
